
import DB.Highscore;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.swing.JComponent;
import javax.swing.JOptionPane;

public class owncanvas extends JComponent {

    private static final long serialVersionUID = 5466794160868309986L;
    public int X = 0,  Y = 0,  height = 400,  width = 550;
    public int spielerPunkte = 0,  schleifenDurchgaenge = 0;
    public int spielerSchuss = 0,  spielerCountdown = 120000; // == 2 minuten
    public boolean zeigeCursor = false,  spielerGeschossen = false;
    public MouseMotionAdapter m;
    public String spielerNick = "anonymous";
    public Vector<target> targets = new Vector<target>();
    public Vector<explosion> explosionen = new Vector<explosion>();

    /**
     * Methode um den Schuß-Sound auszugeben.
     */
    public void shotSound() {
        try {
            AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File(System.getProperty("user.dir") + System.getProperty("file.separator") + "shot.wav"));
            AudioFormat af = audioInputStream.getFormat();
            int size = (int) (af.getFrameSize() * audioInputStream.getFrameLength());
            byte[] audio = new byte[size];
            DataLine.Info info = new DataLine.Info(Clip.class, af, size);
            audioInputStream.read(audio, 0, size);
            // for(int i=0; i < 32; i++) {
            Clip clip = (Clip) AudioSystem.getLine(info);
            clip.open(af, audio, 0, size);
            clip.start();
        // }
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }

    public owncanvas(String Nick) throws Exception {
        this.spielerNick = Nick;
        /**
         * setDoubleBuffered() bewirkt das dem Objekt der Puffer verdoppelt
         * wird, was das Flimmern beim neu zeichnen verindert.
         */
        setDoubleBuffered(true);
        /**
         * Da es kein leeren Maus Cursor gibt wrid hiermit ein neues Cursor
         * Objekt erstellt was unsichtbar ist.
         */
        Cursor c = Toolkit.getDefaultToolkit().createCustomCursor(
                new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB),
                new Point(1, 1), "Custom Cursor");

        setCursor(c);
        
        /**
         * MouseListener um Schüsse ab zu fangen, bzw. deren Mausklicks ^^
         */
        addMouseListener(new MouseAdapter() {

            public void mouseEntered(MouseEvent e) {
                /**
                 * MouseEntered Event, also wenn die Maus das Canvas betritt.
                 *
                 * zeigeCursor Variable auf true setzen
                 * damit Cursor gezeichnet wird.
                 */
                zeigeCursor = true;
            }

            public void mouseExited(MouseEvent e) {
                /**
                 * Mouse Exit Event, also wenn die Maus das Canvas verlässt.
                 *
                 * zeigeCursor Variable auf false setzen
                 * damit Cursor nicht gezeichnet wird.
                 */
                zeigeCursor = false;
            }

            /**
             * MousePressed Event.
             *
             *
             * @param MouseEvent
             */
            @Override
            public void mousePressed(MouseEvent e) {
                shotSound();
                spielerSchuss++;

                /**
                 * setzt Variable spielerGeschossen auf true damit in der Schleife vom Paint event
                 */
                spielerGeschossen = true;
                /**
                 * X und Y stehen für die aktuelle Position des Maus Zeigers,
                 * wird für das abschießen der targets benötigt und später
                 * auch für das Menü.
                 */
                X = e.getX();
                Y = e.getY();
                repaint();
            }
        });
        addMouseMotionListener(new MouseMotionAdapter() {

            /**
             * MouseEvent wenn der Maus Cursor bewegt wird soll
             * die aktuelle Cursor Position in die Globalen
             * X & Y Variablen gespeichert werden und anschließend
             * das canvas neu gezeichnet werden.
             */
            @Override
            public void mouseMoved(MouseEvent e) {
                X = e.getX();
                Y = e.getY();
                repaint();
            }
        });
        Random rnd = new Random();
        int targetsCount;
        do {
            schleifenDurchgaenge++;
            targetsCount = rnd.nextInt(95);
        } while (targetsCount <= 20);

        int i;
        for (i = 0; targetsCount > i; i++) {
            schleifenDurchgaenge++;
            targets.add(new target(rnd.nextInt(width), rnd.nextInt(height), rnd.nextInt(4), rnd.nextInt(3), new Color(rnd.nextFloat(), rnd.nextFloat(), rnd.nextFloat())));
        }

        /**
         * Timer Task um das fallen der Targets zu realisieren
         */
        final Timer timer = new Timer();
        TimerTask task = new TimerTask() {

            public void run() {
                // fallen lassen ^^
                int i = 0;
                for (i = 0; i < targets.size(); i++) {
                    schleifenDurchgaenge++;
                    if ((targets.get(i).getY() + 3) >= height) {
                        targets.get(i).setY(1);
                    } else {
                        targets.get(i).setY(
                                targets.get(i).getY() + targets.get(i).getSpeed());
                    }
                }
                /**
                 * explosionen weiterführen
                 */
                for (i = 0; i < explosionen.size(); i++) {
                    explosionen.get(i).weiter();
                }

                /**
                 * schuss flag auf false setzen damit nicht nach
                 * dem schuss auf ein target navigiert werden
                 * kann das dann zerstört werden soll.
                 */
                spielerGeschossen = false;

                // Bild neu zeichnen
                repaint();
            }
        };

        // Timer zum neu Zeichnen starten (50 milisekunden takt)
        timer.scheduleAtFixedRate(task, 0, 50);

        /**
         * Countdown timer ... danach iss das Spiel
         * zu ende und die punkte sollen eingetragen werden.
         */
        Timer countdown = new Timer();
        TimerTask countdownTask = new TimerTask() {

            public void run() {
                if (spielerCountdown == 0) {
                    timer.cancel();

                    Highscore high = new Highscore();
                    high.newEntry(spielerNick, spielerPunkte);
                    JOptionPane.showInputDialog("du hast punkte: " + spielerPunkte);

                    this.cancel();
                } else {
                    spielerCountdown -= 1000;
                }
            }
        };

        // Timer zum neu Zeichnen starten (50 milisekunden takt)
        countdown.scheduleAtFixedRate(countdownTask, 0, 1000);
    
/* END OF OWNCANVAS() */
    }

    public void paint(Graphics g) {
        // init
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, width, height);

        // targets
        int i = 0;
        for (i = 0; i < targets.size(); i++) {
            schleifenDurchgaenge++;

            /**
             * abfrage ob X,Y Koordinate mit einem der
             * Targets übereinstimmt und
             * spielerSchuss auf true ist (Schuss wurde abgegeben)
             */
            if (spielerGeschossen && (targets.get(i).getX() + targets.get(i).getWIDTH() + 2 >= X) && (targets.get(i).getX() - 2 <= X) && (targets.get(i).getY() + targets.get(i).getHEIGHT() + 2 >= Y) && (targets.get(i).getY() - 2 <= Y)) {

                /**
                 * Berechnung der Punkte
                 * anhand der Target Größe
                 *
                 * je kleiner das Target umso mehr Punkte gibt es.
                 */
                switch (targets.get(i).getSize()) {
                    case 0:
                        spielerPunkte += 10;
                        break;
                    case 1:
                        spielerPunkte += 8;
                        break;
                    case 2:
                        spielerPunkte += 6;
                        break;
                    case 3:
                        spielerPunkte += 4;
                        break;
                    case 4:
                        spielerPunkte += 1;
                        break;
                }

                /**
                 * entfernen des aktuellen Targets
                 */
                targets.remove(i);

                /**
                 * explosion generieren
                 */
                explosionen.add(new explosion(X, Y));


                /**
                 * abfrage ob mehr als 15 Targets vorhanden
                 * sind, wenn nicht 3 neue Targets in zufällig
                 * generierter Position, Größe und Farbe erzeugen.
                 */
                if (targets.size() < 15) {
                    Random rnd = new Random();
                    targets.add(new target(rnd.nextInt(width), rnd.nextInt(height), rnd.nextInt(4), rnd.nextInt(3), new Color(rnd.nextFloat(), rnd.nextFloat(), rnd.nextFloat())));
                    targets.add(new target(rnd.nextInt(width), rnd.nextInt(height), rnd.nextInt(4), rnd.nextInt(3), new Color(rnd.nextFloat(), rnd.nextFloat(), rnd.nextFloat())));
                    targets.add(new target(rnd.nextInt(width), rnd.nextInt(height), rnd.nextInt(4), rnd.nextInt(3), new Color(rnd.nextFloat(), rnd.nextFloat(), rnd.nextFloat())));
                }
                /**
                 * setzt spielerGeschossen auf false damit nur das
                 * auch getroffene target gelöscht wird und nicht alle^^
                 */
                spielerGeschossen = false;
            }


            /**
             * Zeichnet das aktuelle Target indem aus dem Objekt
             * Farbe, Größe und Position geholt wird und
             * als rechteck gezeichnet wird.
             */
            g2d.setColor(targets.get(i).getColor());
            g2d.drawRect(targets.get(i).getX(), targets.get(i).getY(), targets.get(i).getWIDTH(), targets.get(i).getHEIGHT());
        }

        /**
         * Explosionen Zeichnen
         */
        for (i = 0; i < explosionen.size(); i++) {
            for (int u = 0; u < explosionen.get(i).getPunkte().size(); u++) {
                g2d.setColor(explosionen.get(i).getPunkte().get(u).color);
                g2d.drawLine(explosionen.get(i).getPunkte().get(u).x, explosionen.get(i).getPunkte().get(u).y, explosionen.get(i).getPunkte().get(u).x, explosionen.get(i).getPunkte().get(u).y);
            }
        }

        /**
         * Fadenkreuz Zeichnen wenn Cursor sich
         * im canvas befindet (zeigeCursor)
         */
        if (zeigeCursor) {
            //TODO: Überlegen ob es einstellungen geben soll wo man unter verschiedenen Fadenkreuzen auswählen kann ^^
            g2d.setColor(Color.black);
            g2d.drawLine(X + 6, Y, X + 3, Y);
            g2d.drawLine(X, Y + 6, X, Y + 3);
            g2d.drawLine(X - 6, Y, X - 3, Y);
            g2d.drawLine(X, Y - 6, X, Y - 3);
            g2d.setColor(Color.RED);
            g2d.drawLine(X, Y, X, Y);
        }

        // Spielerpunkte anzeigen
        g2d.setFont(new Font("TimesRoman", Font.BOLD, 12));
        g2d.setColor(Color.BLACK);
        g2d.drawString(this.spielerNick + " hat Punkte: " + spielerPunkte + " Schleifen: " + schleifenDurchgaenge + " Targets: " + targets.size() + " Schüsse: " + spielerSchuss + " Countdown: " + spielerCountdown/1000 + " Sekunden ", 5, 10);
    }
}
